package com.fla.minskmap;

import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JOptionPane;

public class MapPanel extends JLabel {
    private static final long serialVersionUID = 2841945178168230708L;

    private static int INCREMENTAL_CIRCLE_ID = 1;

    private List<Circle> drawnCircles;

    private String inputMessage;
    private float numerator;
    private float denominator;

    private Image marker;
    private int markerWidth;
    private int markerHeight;

    public MapPanel(Icon image, String dimension, float numerator, float denominator) {
        super(image);

        this.inputMessage = String.format("Enter radius in %ss", dimension);
        this.numerator = numerator;
        this.denominator = denominator;

        drawnCircles = new ArrayList<Circle>();
        addMouseListener(new ClickListener());

        ImageIcon markerIcon = new ImageIcon("marker.png");

        marker = markerIcon.getImage();
        markerWidth = markerIcon.getIconWidth();
        markerHeight = markerIcon.getIconHeight();
    }

    public Map<String, Float> getDistances() {
        Map<String, Float> distances = new HashMap<String, Float>();

        for (int i = 0; i < drawnCircles.size(); i++) {
            for (int j = i + 1; j < drawnCircles.size(); j++) {
                Circle one = drawnCircles.get(i);
                Circle two = drawnCircles.get(j);

                float distancePx = (float) Math.sqrt(Math.pow(one.x - two.x, 2) + Math.pow(one.y - two.y, 2));
                String key = one.id + " - " + two.id;

                distances.put(key, pxToDimension(distancePx));
            }
        }

        return distances;
    }

    // override paintComponent
    public void paintComponent(Graphics g) {
        super.paintComponent(g);

        for (Circle circle : drawnCircles) {
            int radius = circle.radiusPx;
            int diameter = radius * 2;

            Graphics2D g2d = (Graphics2D) g;
            g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.3f));

            g.setColor(circle.color);
            g.fillOval(circle.x - radius, circle.y - radius, diameter, diameter);

            g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1));
            g.setColor(Color.BLACK);
            g.drawImage(marker, circle.x - markerWidth / 2, circle.y - markerHeight, null);
            g.setFont(new Font("Verdana", Font.BOLD, 14));
            String id = "" + circle.id;
            int shiftX = id.length() == 1 ? 5 : 10;
            g.drawString(id, circle.x - shiftX, circle.y - markerHeight / 2);
        }
        repaint();
    }

    private float dimensionToPx(float dimension) {
        return dimension * numerator / denominator;
    }

    private float pxToDimension(float px) {
        return px * denominator / numerator;
    }

    private void onLeftButtonClicked(int x, int y) {
        String radius = JOptionPane.showInputDialog(inputMessage, JOptionPane.PLAIN_MESSAGE);

        if (radius != null) {
            try {
                float value = Float.valueOf(radius.replaceAll(",", "."));
                if (value > 0) {
                    Circle point = new Circle(x, y, value);
                    drawnCircles.add(point);
                    repaint();
                }
            } catch (NumberFormatException ex) {
                JOptionPane.showMessageDialog(null, "Number format error");
            }
        }
    }

    private void onRightButtonClicked(int x, int y) {
        List<Circle> choosenCircles = new ArrayList<Circle>();
        for (Circle circle : drawnCircles) {
            if (circle.contains(x, y)) {
                choosenCircles.add(circle);
            }
        }

        drawnCircles.removeAll(choosenCircles);
        repaint();
    }

    private class Circle extends Point {
        private int id;
        private int radiusPx;
        private Color color;

        public Circle() {
            super();
        }

        public Circle(int x, int y, float radiusDimension) {
            super(x, y);

            id = INCREMENTAL_CIRCLE_ID++;
            color = generateColor(id);
            radiusPx = (int) dimensionToPx(radiusDimension);
        }

        public Circle(Point p) {
            super(p);
        }

        public boolean contains(int x, int y) {
            return Math.sqrt(Math.pow(super.x - x, 2) + Math.pow(super.y - y, 2)) < radiusPx;
        }
    }

    private class ClickListener extends MouseAdapter {

        @Override
        public void mouseClicked(MouseEvent e) {
            switch (e.getButton()) {
                case MouseEvent.BUTTON1:
                    onLeftButtonClicked(e.getX(), e.getY());
                    break;
                case MouseEvent.BUTTON3:
                    onRightButtonClicked(e.getX(), e.getY());
                    break;
            }
        }
    }

    private Color generateColor(int index) {
        int r = (int) (255 * Math.random());
        int g = (int) (255 * Math.random());
        int b = (int) (255 * Math.random());
        
        return new Color(r, g, b);
    }
}
